import * as Comlink from 'comlink'
import createVideoFrameCapture from './lib/video-frame-capture.js'

class WasmWorker {
  static videoFrameCapture = null
  static generateVideoFrames = null
  static getImageBuffer = null
  load = async () => {
    if(!WasmWorker.videoFrameCapture) {
      WasmWorker.videoFrameCapture = await createVideoFrameCapture()
      WasmWorker.generateVideoFrames = WasmWorker.videoFrameCapture.cwrap('generateVideoFrames', 'number', ['string', 'number', 'number'])
      WasmWorker.getImageBuffer = WasmWorker.videoFrameCapture.cwrap('getImage', 'number', ['number'])
    }
  }
  // 获取视频的所有帧图片
  getAllFramePicture = async (file, width = 200, height = 117) => {
    if(!WasmWorker.videoFrameCapture) {
      await this.load()
    }
    const imageInfos = []
    const fileBuffer = await this.fileToUint8Array(file);
    const filePath = `/${file.name}`
    WasmWorker.videoFrameCapture.FS.writeFile(filePath, fileBuffer)
    const videoFrameCount = WasmWorker.generateVideoFrames(filePath, width, height)
    WasmWorker.videoFrameCapture.FS.unlink(filePath)
    for(let i = 0; i < videoFrameCount; i++) {
      const imageBinaryData = WasmWorker.getImageBuffer(i)
      const imageInfo = this.getImageInfo(imageBinaryData)
      imageInfos.push(imageInfo)
    }
    return imageInfos
  }
  // 获取视频文件有多少帧
  getVideoFrameCount = async (file) => {
    if(!WasmWorker.videoFrameCapture) {
      await this.load()
    }
    const fileBuffer = await this.fileToUint8Array(file);
    const filePath = `/${file.name}`
    WasmWorker.videoFrameCapture.FS.writeFile(filePath, fileBuffer)
    const videoFrameCount = WasmWorker.generateVideoFrames(filePath, 1, 1)
    WasmWorker.videoFrameCapture.FS.unlink(filePath)
    return videoFrameCount
  }
  // 获取视频第index帧的图片
  getVideoFramePictureByIndex = async (file, index, width = 200, height = 117) => {
    if(index < 0) {
      return null
    }
    if(!WasmWorker.videoFrameCapture) {
      await this.load()
    }
    const fileBuffer = await this.fileToUint8Array(file);
    const filePath = `/${file.name}`
    WasmWorker.videoFrameCapture.FS.writeFile(filePath, fileBuffer)
    const videoFrameCount = WasmWorker.generateVideoFrames(filePath, width, height)
    WasmWorker.videoFrameCapture.FS.unlink(filePath)
    if(index > videoFrameCount) {
      return null
    }
    const imageBinaryData = WasmWorker.getImageBuffer(index)
    const imageInfo = this.getImageInfo(imageBinaryData)
    return imageInfo
  }
  getImageInfo = (imgDataPtr) => {
    let width = WasmWorker.videoFrameCapture.HEAPU32[imgDataPtr / 4],
      height = WasmWorker.videoFrameCapture.HEAPU32[imgDataPtr / 4 + 1],
      imageBufferPtr = WasmWorker.videoFrameCapture.HEAPU32[imgDataPtr / 4 + 2],
      imageBuffer = WasmWorker.videoFrameCapture.HEAPU8.slice(imageBufferPtr, imageBufferPtr + width * height * 3);
    const imageDataBuffer = new Uint8ClampedArray(width * height * 4);
    let j = 0;
    for (let i = 0; i < imageBuffer.length; i++) {
      if (i && i % 3 == 0) {
        imageDataBuffer[j] = 255;
        j += 1;
      }
      imageDataBuffer[j] = imageBuffer[i];
      j += 1;
    }
    return {
      width,
      height,
      imageDataBuffer
    };
  }
  fileToUint8Array = (file) => {
    return this.fileToBuf(file).then(buff => {
      return new Uint8Array(buff)
    })
  }
  fileToBuf = (file) => {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.readAsArrayBuffer(file);
      reader.onload = (event) => {
        if(event.target.error) {
          reject(event.target.error)
        } else {
          resolve(event.target.result)
        }
      }
      reader.onerror = (e) => {
        reject(e)
      }
    })
  }
}

Comlink.expose(WasmWorker)